﻿using Abp.Domain.Entities;
using Abp.Domain.Repositories;
using Abp.Domain.Uow;
using Abp.UI;
using FwProject.Core.Restaurant;
using FwProject.Core.SettlementInfoModel;
using FwProject.Distribution;
using FwProject.PrePaymentInfo.Dto;
using FwProject.Restaurant;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using X.PagedList;

namespace FwProject.PrePaymentInfo
{
    public class FinanceReportAppService : FwProjectAppServiceBase, IFinanceReportAppService
    {
        private readonly IDistributionAppService _distributionAppService;
        private readonly IRepository<SettlementInfo, Guid> _repositorySettlementInfo;
        private readonly IRepository<PrePaymentInfoModel, Guid> _repositoryPrePayment;
        private readonly IRepository<ReceiptInfoBySettlementModel, Guid> _repositoryReceiptInfoBySettlementModel;
        private readonly IRepository<DepositInfo, Guid> _repositoryDeposit;
        private readonly IRepository<ReceiptInfoModel, Guid> _repositoryReceiptInfo;
        private readonly IRepository<RestaurantInfo, Guid> _repositoryRestaurantInfo;
        private readonly IRepository<SettlementAccount, Guid> _repositorySettlementAccount;
        private readonly IRepository<LoadCar, Guid> _repositoryLoadCar;

        private readonly IUnitOfWorkManager _unitOfWorkManager;
        public FinanceReportAppService(IDistributionAppService distributionAppService,
            IRepository<SettlementInfo, Guid> repositorySettlementInfo,
            IRepository<PrePaymentInfoModel, Guid> repositoryPrePayment,
            IRepository<ReceiptInfoBySettlementModel, Guid> repositoryReceiptInfoBySettlementModel,
            IRepository<DepositInfo, Guid> repositoryDeposit,
            IRepository<ReceiptInfoModel, Guid> repositoryReceiptInfo,
            IRepository<RestaurantInfo, Guid> repositoryRestaurantInfo,
            IRepository<SettlementAccount, Guid> repositorySettlementAccount,
            IRepository<LoadCar, Guid> repositoryLoadCar,
            IUnitOfWorkManager unitOfWorkManager)
        {
            _unitOfWorkManager = unitOfWorkManager;
            _distributionAppService = distributionAppService;
            _repositorySettlementInfo = repositorySettlementInfo;
            _repositoryPrePayment = repositoryPrePayment;
            _repositoryReceiptInfoBySettlementModel = repositoryReceiptInfoBySettlementModel;
            _repositoryDeposit = repositoryDeposit;
            _repositoryReceiptInfo = repositoryReceiptInfo;
            _repositoryRestaurantInfo = repositoryRestaurantInfo;
            _repositorySettlementAccount = repositorySettlementAccount;
            _repositoryLoadCar = repositoryLoadCar;
        }

        public async Task<FinanceSummaryOutputDto> GetFinanceSummaryAsync(DateTime? beginTime, DateTime? endTime)
        {
            FinanceSummaryOutputDto dto = new FinanceSummaryOutputDto();
            dto.DistributionProductStatistics = await _distributionAppService.GetDistributionProductStatisticsAsync(beginTime, endTime, "", "");

            var factory = (await base.GetCurrentUserAsync()).FactoryinfoId;
            #region 应收统计
            //应收统计
            ReceivableStatisticsDto receivableStatistics = new ReceivableStatisticsDto();

            //期初单据应收金额（开始时间以前的应收金额）
            receivableStatistics.InitialReceivableMoney = _repositorySettlementInfo.GetAll().Where(o => o.CreationTime < beginTime && (o.RestaurantPayStatus != RestaurantPayStatus.作废 || o.RestaurantPayStatus != RestaurantPayStatus.坏账确认) && o.FactoryinfoId == factory).Sum(o => o.Totalprice - o.ReceivedPrice - o.Discountprice - o.ReceivedDiscount - o.UsePrePayment);


            var period = _repositorySettlementInfo.GetAll().Where(o => o.CreationTime > beginTime && o.CreationTime < endTime.Value.AddDays(1) && (o.RestaurantPayStatus != RestaurantPayStatus.作废 || o.RestaurantPayStatus != RestaurantPayStatus.坏账确认) && o.FactoryinfoId == factory).Select(o => new { o.Actualprice, o.Discountprice, o.ReceivedDiscount, o.ReceivedPrice, o.UsePrePayment, o.Totalprice }).ToList();

            //本期增加应收金额（该时间段内的的应收金额）
            receivableStatistics.PeriodIncreasedReceivableMoney = period.Sum(o => o.Totalprice);

            //本期优惠金额
            receivableStatistics.PeriodPreferentialMoney = period.Sum(o => o.Discountprice + o.ReceivedDiscount);

            //本期收款金额
            receivableStatistics.PeriodReceiptMoney = period.Sum(o => o.ReceivedPrice);

            //本期使用预收挎包
            receivableStatistics.PeriodUsePrepaymentsMoney = period.Sum(o => o.UsePrePayment);


            //var q1 = _repositorySettlementInfo.GetAll().Where(o => o.CreationTime < endTime && o.ExamineStatus == Core.SettlementInfoModel.ExamineStatus.已审核 && (o.RestaurantPayStatus == RestaurantPayStatus.未收款 || o.RestaurantPayStatus == RestaurantPayStatus.部分收款));
            //期末应收金额(结束时间以前的所有应收)
            receivableStatistics.FinalReceivableMoney = _repositorySettlementInfo.GetAll().Where(o => o.CreationTime < endTime.Value.AddDays(1) && (o.RestaurantPayStatus != RestaurantPayStatus.作废 || o.RestaurantPayStatus != RestaurantPayStatus.坏账确认)).Sum(o => o.Totalprice - o.ReceivedPrice - o.Discountprice - o.ReceivedDiscount - o.UsePrePayment);


            #region 预收款
            //期初预收款金额
            var list = await _repositoryPrePayment.GetAll().Where(o => o.CreationTime < beginTime && o.FactoryinfoId == factory).ToListAsync();
            //已预交金额
            var already = list.Where(o => o.PrePaymentInfoType == PrePaymentInfoType.收预交金).Sum(o => o.PrePaymentPrice);
            //已退金额
            var retired = list.Where(o => o.PrePaymentInfoType == PrePaymentInfoType.退预交金).Sum(o => o.PrePaymentPrice);

            //已使用的预收金
            var use = _repositoryReceiptInfoBySettlementModel.GetAll().Where(o => o.CreationTime < beginTime && o.FactoryinfoId == factory).Sum(o => o.UsePrePayment);
            receivableStatistics.InitialPrepaymentsMoney = already - retired - use;

            var periodPrepayments = _repositoryPrePayment.GetAll().Where(o => o.CreationTime > beginTime && o.CreationTime < endTime.Value.AddDays(1) && o.FactoryinfoId == factory).Select(o => new { o.PrePaymentInfoType, o.PrePaymentPrice });
            //本期回收预收金
            receivableStatistics.PeriodRecyclingPrepaymentsMoney = periodPrepayments.Where(o => o.PrePaymentInfoType == PrePaymentInfoType.收预交金).Sum(o => o.PrePaymentPrice);

            //本期核销预收金（已使用加退还）
            receivableStatistics.PeriodWriteOffPrepaymentsMoney = period.Sum(o => o.UsePrePayment) + periodPrepayments.Where(o => o.PrePaymentInfoType == PrePaymentInfoType.退预交金).Sum(o => o.PrePaymentPrice);



            #endregion


            dto.ReceivableStatistics = receivableStatistics;
            #endregion

            #region 押金统计
            DepositStatisticsDto depositStatistics = new DepositStatisticsDto();
            //期初押金余额
            var alreadyDeposit = _repositoryDeposit.GetAll().Where(o => o.FactoryinfoId == factory && o.DepositTime < beginTime && o.DepositType == DepositType.收押金).Sum(o => o.Money);
            var returnDeposit = _repositoryDeposit.GetAll().Where(o => o.FactoryinfoId == factory && o.DepositTime < beginTime && o.DepositType == DepositType.退押金).Sum(o => o.Money);
            depositStatistics.InitialDepositMoney = alreadyDeposit - returnDeposit;

            //本期收回押金金额
            depositStatistics.PeriodRecyclingDepositMoney = _repositoryDeposit.GetAll().Where(o => o.FactoryinfoId == factory && o.DepositTime > beginTime && o.DepositTime < endTime.Value.AddDays(1) && o.DepositType == DepositType.收押金).Sum(o => o.Money);

            //本期退回押金金额
            depositStatistics.PeriodReturnDepositMoney = _repositoryDeposit.GetAll().Where(o => o.FactoryinfoId == factory && o.DepositTime > beginTime && o.DepositTime < endTime.Value.AddDays(1) && o.DepositType == DepositType.退押金).Sum(o => o.Money);

            dto.DepositStatistics = depositStatistics;
            #endregion


            return dto;

        }
        /// <summary>
        /// 客户往来流水账
        /// </summary>
        /// <returns></returns>
        public async Task<IPagedList<RunningAccountDto>> GetRunningAccountPagedListAsync(int pageIdx, int pageSize, DateTime? beginTime, DateTime? endTime, string RestaurantName)
        {
            var user = await base.GetCurrentUserAsync();

            var data = _repositoryReceiptInfo.GetAllIncluding(o => o.RestaurantInfoModel).Where(o => o.FactoryinfoId == user.FactoryinfoId && o.ToVoid == ToVoidStatus.未作废).Select(o => new { RestaurantId = o.RestaurantId, BillType = BillTypeEnum.收款单, BillNumber = o.ReceiptInfoNumber, BillDate = o.CreationTime, AccountId = o.CapitalAccountId, Amount = o.TaskBackAmount, RemarkContent = o.RemarksConten });

            data = data.Union(_repositoryDeposit.GetAllIncluding(o => o.RestaurantInfoModel).Where(o => o.DepositType == DepositType.收押金 && o.FactoryinfoId == user.FactoryinfoId).Select(o => new { RestaurantId = o.RestaurantId, BillType = BillTypeEnum.收押金, BillNumber = o.CreationNumber, BillDate = o.DepositTime, AccountId = o.CapitalAccountId.Value, Amount = o.Money, RemarkContent = o.RemarkContent }));

            data = data.Union(_repositoryDeposit.GetAllIncluding(o => o.RestaurantInfoModel).Where(o => o.DepositType == DepositType.退押金 && o.FactoryinfoId == user.FactoryinfoId).Select(o => new { RestaurantId = o.RestaurantId, BillType = BillTypeEnum.退押金, BillNumber = o.CreationNumber, BillDate = o.DepositTime, AccountId = o.CapitalAccountId.Value, Amount = o.Money, RemarkContent = o.RemarkContent }));

            data = data.Union(_repositoryPrePayment.GetAll().Where(o => o.PrePaymentInfoType == PrePaymentInfoType.收预交金 && o.FactoryinfoId == user.FactoryinfoId).Select(o => new { RestaurantId = o.RestaurantInfoId, BillType = BillTypeEnum.预收款单, BillNumber = o.PrePaymentInfoNumber, BillDate = o.CreationTime, AccountId = o.CapitalAccountId, Amount = o.PrePaymentPrice, RemarkContent = o.RemarkContent }));

            data = data.Union(_repositoryPrePayment.GetAll().Where(o => o.PrePaymentInfoType == PrePaymentInfoType.退预交金 && o.FactoryinfoId == user.FactoryinfoId).Select(o => new { RestaurantId = o.RestaurantInfoId, BillType = BillTypeEnum.退还预收款, BillNumber = o.PrePaymentInfoNumber, BillDate = o.CreationTime, AccountId = o.CapitalAccountId, Amount = o.PrePaymentPrice, RemarkContent = o.RemarkContent }));

            var list = data.Join(_repositoryRestaurantInfo.GetAll(), a => a.RestaurantId, b => b.Id, (a, b) => new
            {
                a.RestaurantId,
                b.RestaurantName,
                a.BillType,
                a.BillNumber,
                a.BillDate,
                a.AccountId,
                a.Amount,
                a.RemarkContent
            }).Join(_repositorySettlementAccount.GetAll(), a => a.AccountId, b => b.Id, (a, b) => new RunningAccountDto
            {
                RestaurantId = a.RestaurantId,
                RestaurantName = a.RestaurantName,
                BillType = a.BillType,
                BillNumber = a.BillNumber,
                BillDate = a.BillDate,
                AccountId = a.AccountId,
                AccountName = b.Name,
                Amount = a.Amount,
                RemarkContent = a.RemarkContent
            });

            if (beginTime.HasValue)
                list = list.Where(o => o.BillDate >= beginTime);

            if (endTime.HasValue)
                list = list.Where(o => o.BillDate <= endTime.Value.AddHours(24));

            if (!string.IsNullOrEmpty(RestaurantName))
                list = list.Where(o => o.RestaurantName.Contains(RestaurantName));

            return await list.OrderByDescending(o => o.BillDate).ToPagedListAsync(pageIdx, pageSize);
        }

        public async Task<List<RunningAccountDto>> GetRunningAccountListAsync(DateTime? beginTime, DateTime? endTime, string RestaurantName)
        {
            var user = await base.GetCurrentUserAsync();

            var data = _repositoryReceiptInfo.GetAllIncluding(o => o.RestaurantInfoModel).Where(o => o.FactoryinfoId == user.FactoryinfoId).Select(o => new { RestaurantId = o.RestaurantId, BillType = BillTypeEnum.收款单, BillNumber = o.ReceiptInfoNumber, BillDate = o.CreationTime, AccountId = o.CapitalAccountId, Amount = o.TaskBackAmount, RemarkContent = o.RemarksConten });

            data = data.Union(_repositoryDeposit.GetAllIncluding(o => o.RestaurantInfoModel).Where(o => o.DepositType == DepositType.收押金 && o.FactoryinfoId == user.FactoryinfoId).Select(o => new { RestaurantId = o.RestaurantId, BillType = BillTypeEnum.收押金, BillNumber = o.CreationNumber, BillDate = o.CreationTime, AccountId = o.CapitalAccountId.Value, Amount = Convert.ToDecimal(o.Money), RemarkContent = o.RemarkContent }));

            data = data.Union(_repositoryDeposit.GetAllIncluding(o => o.RestaurantInfoModel).Where(o => o.DepositType == DepositType.退押金 && o.FactoryinfoId == user.FactoryinfoId).Select(o => new { RestaurantId = o.RestaurantId, BillType = BillTypeEnum.退押金, BillNumber = o.CreationNumber, BillDate = o.CreationTime, AccountId = o.CapitalAccountId.Value, Amount = Convert.ToDecimal(o.Money), RemarkContent = o.RemarkContent }));

            data = data.Union(_repositoryPrePayment.GetAll().Where(o => o.PrePaymentInfoType == PrePaymentInfoType.收预交金 && o.FactoryinfoId == user.FactoryinfoId).Select(o => new { RestaurantId = o.RestaurantInfoId, BillType = BillTypeEnum.预收款单, BillNumber = o.PrePaymentInfoNumber, BillDate = o.CreationTime, AccountId = o.CapitalAccountId, Amount = o.PrePaymentPrice, RemarkContent = o.RemarkContent }));

            data = data.Union(_repositoryPrePayment.GetAll().Where(o => o.PrePaymentInfoType == PrePaymentInfoType.退预交金 && o.FactoryinfoId == user.FactoryinfoId).Select(o => new { RestaurantId = o.RestaurantInfoId, BillType = BillTypeEnum.退还预收款, BillNumber = o.PrePaymentInfoNumber, BillDate = o.CreationTime, AccountId = o.CapitalAccountId, Amount = o.PrePaymentPrice, RemarkContent = o.RemarkContent }));

            var list = data.Join(_repositoryRestaurantInfo.GetAll(), a => a.RestaurantId, b => b.Id, (a, b) => new
            {
                a.RestaurantId,
                b.RestaurantName,
                a.BillType,
                a.BillNumber,
                a.BillDate,
                a.AccountId,
                a.Amount,
                a.RemarkContent
            }).Join(_repositorySettlementAccount.GetAll(), a => a.AccountId, b => b.Id, (a, b) => new RunningAccountDto
            {
                RestaurantId = a.RestaurantId,
                RestaurantName = a.RestaurantName,
                BillType = a.BillType,
                BillNumber = a.BillNumber,
                BillDate = a.BillDate,
                AccountId = a.AccountId,
                AccountName = b.Name,
                Amount = a.Amount,
                RemarkContent = a.RemarkContent
            });

            if (beginTime.HasValue)
                list = list.Where(o => o.BillDate >= beginTime);

            if (endTime.HasValue)
                list = list.Where(o => o.BillDate <= endTime.Value.AddHours(24));

            if (!string.IsNullOrEmpty(RestaurantName))
                list = list.Where(o => o.RestaurantName.Contains(RestaurantName));

            return await list.OrderByDescending(o => o.BillDate).ToListAsync();
        }


        public async Task<IPagedList<SettleAccountsKnowingOutputDto>> GetSettleAccountsKnowingDetailAsync(int pageIdx, int pageSize, DateTime? beginTime, DateTime? endTime, Guid? accountId)
        {
            var factory = (await base.GetCurrentUserAsync()).FactoryinfoId;
            var query = _repositoryReceiptInfo.GetAllIncluding(o => o.RestaurantInfoModel).Where(o => o.FactoryinfoId == factory).Select(o => new { DocumentType = BillTypeEnum.收款单, DocumentNumber = o.ReceiptInfoNumber, CreationTime = o.CreationTime, RestaurantId = o.RestaurantId, AgentPeoper = o.AgentPeoper, SettlementAccount = o.CapitalAccountId, Income = o.TaskBackAmount, Expenditure = 0m });

            query = query.Union(_repositoryDeposit.GetAllIncluding(o => o.RestaurantInfoModel).Where(o => o.DepositType == DepositType.收押金 && o.FactoryinfoId == factory).Select(o => new { DocumentType = BillTypeEnum.收押金, DocumentNumber = o.CreationNumber, CreationTime = o.DepositTime, RestaurantId = o.RestaurantId, AgentPeoper = o.AgentPeoper, SettlementAccount = o.CapitalAccountId.Value, Income = (decimal)o.Money, Expenditure = 0m }));

            query = query.Union(_repositoryDeposit.GetAllIncluding(o => o.RestaurantInfoModel).Where(o => o.DepositType == DepositType.退押金 && o.FactoryinfoId == factory).Select(o => new { DocumentType = BillTypeEnum.退押金, DocumentNumber = o.CreationNumber, CreationTime = o.DepositTime, RestaurantId = o.RestaurantId, AgentPeoper = o.AgentPeoper, SettlementAccount = o.CapitalAccountId.Value, Income = 0m, Expenditure = (decimal)o.Money }));

            query = query.Union(_repositoryPrePayment.GetAll().Where(o => o.PrePaymentInfoType == PrePaymentInfoType.收预交金 && o.FactoryinfoId == factory).Select(o => new { DocumentType = BillTypeEnum.预收款单, DocumentNumber = o.PrePaymentInfoNumber, CreationTime = o.CreationTime, RestaurantId = o.RestaurantInfoId, AgentPeoper = o.AgentPeoper, SettlementAccount = o.CapitalAccountId, Income = o.PrePaymentPrice, Expenditure = 0m }));

            query = query.Union(_repositoryPrePayment.GetAll().Where(o => o.PrePaymentInfoType == PrePaymentInfoType.退预交金 && o.FactoryinfoId == factory).Select(o => new { DocumentType = BillTypeEnum.退还预收款, DocumentNumber = o.PrePaymentInfoNumber, CreationTime = o.CreationTime, RestaurantId = o.RestaurantInfoId, AgentPeoper = o.AgentPeoper, SettlementAccount = o.CapitalAccountId, Income = 0m, Expenditure = o.PrePaymentPrice }));


            var query2 = query.Join(_repositoryRestaurantInfo.GetAll().Where(o => o.FactoryinfoId == factory), i => i.RestaurantId, j => j.Id, (i, j) => new
            {
                DocumentType = i.DocumentType,
                DocumentNumber = i.DocumentNumber,
                CreationTime = i.CreationTime,
                RestaurantName = j.RestaurantName,
                AgentPeoper = i.AgentPeoper,
                SettlementAccountId = i.SettlementAccount,
                Income = i.Income,
                Expenditure = i.Expenditure
            }).Join(_repositorySettlementAccount.GetAll(), i => i.SettlementAccountId, j => j.Id, (i, j) =>
            new SettleAccountsKnowingOutputDto
            {
                DocumentType = i.DocumentType,
                DocumentNumber = i.DocumentNumber,
                CreationTime = i.CreationTime,
                RestaurantName = i.RestaurantName,
                AgentPeoper = i.AgentPeoper,
                SettlementAccountId = i.SettlementAccountId,
                SettlementAccount = j.Name,
                Income = i.Income,
                Expenditure = i.Expenditure
            });

            if (beginTime.HasValue)
                query2 = query2.Where(o => o.CreationTime > beginTime);

            if (endTime.HasValue)
                query2 = query2.Where(o => o.CreationTime < endTime.Value.AddDays(1));

            if (accountId.HasValue)
                query2 = query2.Where(o=>o.SettlementAccountId==accountId.Value);

            return await query2.OrderByDescending(o => o.CreationTime).ThenBy(o => o.SettlementAccount).ToPagedListAsync(pageIdx, pageSize);

        }

        public async Task<List<SettleAccountsKnowingOutputDto>> GetSettleAccountsKnowingDetailListAsync(DateTime? beginTime, DateTime? endTime, Guid? accountId)
        {
            var factory = (await base.GetCurrentUserAsync()).FactoryinfoId;
            var query = _repositoryReceiptInfo.GetAllIncluding(o => o.RestaurantInfoModel).Where(o => o.FactoryinfoId == factory).Select(o => new { DocumentType = BillTypeEnum.收款单, DocumentNumber = o.ReceiptInfoNumber, CreationTime = o.CreationTime, RestaurantId = o.RestaurantId, AgentPeoper = o.AgentPeoper, SettlementAccount = o.CapitalAccountId, Income = o.TaskBackAmount, Expenditure = 0m });

            query = query.Union(_repositoryDeposit.GetAllIncluding(o => o.RestaurantInfoModel).Where(o => o.DepositType == DepositType.收押金 && o.FactoryinfoId == factory).Select(o => new { DocumentType = BillTypeEnum.收押金, DocumentNumber = o.CreationNumber, CreationTime = o.DepositTime, RestaurantId = o.RestaurantId, AgentPeoper = o.AgentPeoper, SettlementAccount = o.CapitalAccountId.Value, Income = (decimal)o.Money, Expenditure = 0m }));

            query = query.Union(_repositoryDeposit.GetAllIncluding(o => o.RestaurantInfoModel).Where(o => o.DepositType == DepositType.退押金 && o.FactoryinfoId == factory).Select(o => new { DocumentType = BillTypeEnum.退押金, DocumentNumber = o.CreationNumber, CreationTime = o.DepositTime, RestaurantId = o.RestaurantId, AgentPeoper = o.AgentPeoper, SettlementAccount = o.CapitalAccountId.Value, Income = 0m, Expenditure = (decimal)o.Money }));

            query = query.Union(_repositoryPrePayment.GetAll().Where(o => o.PrePaymentInfoType == PrePaymentInfoType.收预交金 && o.FactoryinfoId == factory).Select(o => new { DocumentType = BillTypeEnum.预收款单, DocumentNumber = o.PrePaymentInfoNumber, CreationTime = o.CreationTime, RestaurantId = o.RestaurantInfoId, AgentPeoper = o.AgentPeoper, SettlementAccount = o.CapitalAccountId, Income = o.PrePaymentPrice, Expenditure = 0m }));

            query = query.Union(_repositoryPrePayment.GetAll().Where(o => o.PrePaymentInfoType == PrePaymentInfoType.退预交金 && o.FactoryinfoId == factory).Select(o => new { DocumentType = BillTypeEnum.退还预收款, DocumentNumber = o.PrePaymentInfoNumber, CreationTime = o.CreationTime, RestaurantId = o.RestaurantInfoId, AgentPeoper = o.AgentPeoper, SettlementAccount = o.CapitalAccountId, Income = 0m, Expenditure = o.PrePaymentPrice }));


            var query2 = query.Join(_repositoryRestaurantInfo.GetAll().Where(o => o.FactoryinfoId == factory), i => i.RestaurantId, j => j.Id, (i, j) => new
            {
                DocumentType = i.DocumentType,
                DocumentNumber = i.DocumentNumber,
                CreationTime = i.CreationTime,
                RestaurantName = j.RestaurantName,
                AgentPeoper = i.AgentPeoper,
                SettlementAccountId = i.SettlementAccount,
                Income = i.Income,
                Expenditure = i.Expenditure
            }).Join(_repositorySettlementAccount.GetAll(), i => i.SettlementAccountId, j => j.Id, (i, j) =>
            new SettleAccountsKnowingOutputDto
            {
                DocumentType = i.DocumentType,
                DocumentNumber = i.DocumentNumber,
                CreationTime = i.CreationTime,
                RestaurantName = i.RestaurantName,
                AgentPeoper = i.AgentPeoper,
                SettlementAccountId = i.SettlementAccountId,
                SettlementAccount = j.Name,
                Income = i.Income,
                Expenditure = i.Expenditure
            });

            if (beginTime.HasValue)
                query2 = query2.Where(o => o.CreationTime > beginTime);

            if (endTime.HasValue)
                query2 = query2.Where(o => o.CreationTime < endTime.Value.AddDays(1));

            if (accountId.HasValue)
                query2 = query2.Where(o => o.SettlementAccountId == accountId.Value);

            return await query2.OrderByDescending(o => o.CreationTime).ThenBy(o => o.SettlementAccount).ToListAsync();
        }
        /// <summary>
        /// 每日收支汇总
        /// </summary>
        /// <returns></returns>
        public async Task<SummaryDailyIncomeAndExpensesDto> GetDailyIncomeAndExpensesAsync(int pageIdx, int pageSize, DateTime? beginTime, DateTime? endTime)
        {
            if (beginTime.HasValue == false || endTime.HasValue == false)
                throw new UserFriendlyException("请输入查询日期！");

            var factoryid = (await base.GetCurrentUserAsync()).FactoryinfoId;

            var receipt = _repositoryReceiptInfo.GetAll().Where(o => o.FactoryinfoId == factoryid).GroupBy(o => o.CreationTime.Date).Select(s => new { CreationTime = s.Key, Money = s.Sum(y => y.TaskBackAmount) });
            var collectDeposit = _repositoryDeposit.GetAll().Where(o => o.FactoryinfoId == factoryid && o.DepositType == DepositType.收押金).GroupBy(o => o.DepositTime.Date).Select(s => new { CreationTime = s.Key, Money = Convert.ToDecimal(s.Sum(y => y.Money)) });
            var collectPrePayment = _repositoryPrePayment.GetAll().Where(o => o.FactoryinfoId == factoryid && o.PrePaymentInfoType == PrePaymentInfoType.收预交金).GroupBy(o => o.CreationTime.Date).Select(s => new { CreationTime = s.Key, Money = s.Sum(y => y.PrePaymentPrice) });
            var returnDeposit = _repositoryDeposit.GetAll().Where(o => o.FactoryinfoId == factoryid && o.DepositType == DepositType.退押金).GroupBy(o => o.DepositTime.Date).Select(s => new { CreationTime = s.Key, Money = Convert.ToDecimal(s.Sum(y => y.Money)) });
            var returnPrePayment = _repositoryPrePayment.GetAll().Where(o => o.FactoryinfoId == factoryid && o.PrePaymentInfoType == PrePaymentInfoType.退预交金).GroupBy(o => o.CreationTime.Date).Select(s => new { CreationTime = s.Key, Money = s.Sum(y => y.PrePaymentPrice) });

            if (beginTime.HasValue)
            {
                receipt = receipt.Where(o => o.CreationTime >= beginTime);
                collectDeposit = collectDeposit.Where(o => o.CreationTime >= beginTime);
                collectPrePayment = collectPrePayment.Where(o => o.CreationTime >= beginTime);
                returnDeposit = returnDeposit.Where(o => o.CreationTime >= beginTime);
                returnPrePayment = returnPrePayment.Where(o => o.CreationTime >= beginTime);
            }
            if (endTime.HasValue)
            {
                receipt = receipt.Where(o => o.CreationTime <= endTime.Value.AddDays(1));
                collectDeposit = collectDeposit.Where(o => o.CreationTime <= endTime.Value.AddDays(1));
                collectPrePayment = collectPrePayment.Where(o => o.CreationTime <= endTime.Value.AddDays(1));
                returnDeposit = returnDeposit.Where(o => o.CreationTime <= endTime.Value.AddDays(1));
                returnPrePayment = returnPrePayment.Where(o => o.CreationTime <= endTime.Value.AddDays(1));
            }
            TimeSpan diff = endTime.Value.AddDays(1).Date - beginTime.Value.Date;
            List<DateTime> list = new List<DateTime>();
            if (diff.Days == 0)
                list.Add(beginTime.Value.Date);
            if (diff.Days > 0)
            {
                for (int i = 0; i < diff.Days; i++)
                {
                    list.Add(beginTime.Value.AddDays(i).Date);
                }
            }

            var data = list.GroupJoin(receipt, i => i.Date, b => b.CreationTime, (i, b) => new
            {
                CreationTime = i.Date,
                Money = b.Sum(s => s.Money)
            }).GroupJoin(collectDeposit, a => a.CreationTime, b => b.CreationTime, (a, b) => new
            {
                a.CreationTime,
                Money = a.Money + b.Sum(s => s.Money)
            }).GroupJoin(collectPrePayment, a => a.CreationTime, b => b.CreationTime, (a, b) => new
            {
                a.CreationTime,
                Income = a.Money + b.Sum(s => s.Money)
            }).GroupJoin(returnDeposit, a => a.CreationTime, b => b.CreationTime, (a, b) => new
            {
                a.CreationTime,
                a.Income,
                Money = b.Sum(s => s.Money)
            }).GroupJoin(returnPrePayment, a => a.CreationTime, b => b.CreationTime, (a, b) => new
            {
                a.CreationTime,
                a.Income,
                Expenses = a.Money + b.Sum(s => s.Money)
            }).Select(s => new DailyIncomeAndExpensesDto
            {
                Date = s.CreationTime,
                Income = s.Income,
                Expenses = s.Expenses,
                Difference = s.Income - s.Expenses
            });
            var pagelist = await data.OrderByDescending(o => o.Date).ToPagedListAsync(pageIdx, pageSize);

            SummaryDailyIncomeAndExpensesDto dto = new SummaryDailyIncomeAndExpensesDto();

            dto.pagelist = pagelist;
            dto.SumIncome = data.Sum(o => o.Income);
            dto.SumExpenses = data.Sum(o => o.Expenses);
            dto.SumDifference = data.Sum(o => o.Difference);

            return dto;
        }


        public async Task<List<DailyIncomeAndExpensesDto>> GetDailyIncomeAndExpensesAllListAsync(DateTime? beginTime, DateTime? endTime)
        {
            if (beginTime.HasValue == false || endTime.HasValue == false)
                throw new UserFriendlyException("请输入查询日期！");

            var factoryid = (await base.GetCurrentUserAsync()).FactoryinfoId;

            var receipt = _repositoryReceiptInfo.GetAll().Where(o => o.FactoryinfoId == factoryid).GroupBy(o => o.CreationTime.Date).Select(s => new { CreationTime = s.Key, Money = s.Sum(y => y.TaskBackAmount) });
            var collectDeposit = _repositoryDeposit.GetAll().Where(o => o.FactoryinfoId == factoryid && o.DepositType == DepositType.收押金).GroupBy(o => o.DepositTime.Date).Select(s => new { CreationTime = s.Key, Money = Convert.ToDecimal(s.Sum(y => y.Money)) });
            var collectPrePayment = _repositoryPrePayment.GetAll().Where(o => o.FactoryinfoId == factoryid && o.PrePaymentInfoType == PrePaymentInfoType.收预交金).GroupBy(o => o.CreationTime.Date).Select(s => new { CreationTime = s.Key, Money = s.Sum(y => y.PrePaymentPrice) });
            var returnDeposit = _repositoryDeposit.GetAll().Where(o => o.FactoryinfoId == factoryid && o.DepositType == DepositType.退押金).GroupBy(o => o.DepositTime.Date).Select(s => new { CreationTime = s.Key, Money = Convert.ToDecimal(s.Sum(y => y.Money)) });
            var returnPrePayment = _repositoryPrePayment.GetAll().Where(o => o.FactoryinfoId == factoryid && o.PrePaymentInfoType == PrePaymentInfoType.退预交金).GroupBy(o => o.CreationTime.Date).Select(s => new { CreationTime = s.Key, Money = s.Sum(y => y.PrePaymentPrice) });

            if (beginTime.HasValue)
            {
                receipt = receipt.Where(o => o.CreationTime >= beginTime);
                collectDeposit = collectDeposit.Where(o => o.CreationTime >= beginTime);
                collectPrePayment = collectPrePayment.Where(o => o.CreationTime >= beginTime);
                returnDeposit = returnDeposit.Where(o => o.CreationTime >= beginTime);
                returnPrePayment = returnPrePayment.Where(o => o.CreationTime >= beginTime);
            }
            if (endTime.HasValue)
            {
                receipt = receipt.Where(o => o.CreationTime <= endTime.Value.AddHours(24));
                collectDeposit = collectDeposit.Where(o => o.CreationTime <= endTime.Value.AddHours(24));
                collectPrePayment = collectPrePayment.Where(o => o.CreationTime <= endTime.Value.AddHours(24));
                returnDeposit = returnDeposit.Where(o => o.CreationTime <= endTime.Value.AddHours(24));
                returnPrePayment = returnPrePayment.Where(o => o.CreationTime <= endTime.Value.AddHours(24));
            }
            TimeSpan diff = endTime.Value.AddDays(1).Date - beginTime.Value.Date;
            List<DateTime> list = new List<DateTime>();
            if (diff.Days == 0)
                list.Add(beginTime.Value.Date);
            if (diff.Days > 0)
            {
                for (int i = 0; i < diff.Days; i++)
                {
                    list.Add(beginTime.Value.AddDays(i).Date);
                }
            }

            var data = list.GroupJoin(receipt, i => i.Date, b => b.CreationTime, (i, b) => new
            {
                CreationTime = i.Date,
                Money = b.Sum(s => s.Money)
            }).GroupJoin(collectDeposit, a => a.CreationTime, b => b.CreationTime, (a, b) => new
            {
                a.CreationTime,
                Money = a.Money + b.Sum(s => s.Money)
            }).GroupJoin(collectPrePayment, a => a.CreationTime, b => b.CreationTime, (a, b) => new
            {
                a.CreationTime,
                Income = a.Money + b.Sum(s => s.Money)
            }).GroupJoin(returnDeposit, a => a.CreationTime, b => b.CreationTime, (a, b) => new
            {
                a.CreationTime,
                a.Income,
                Money = b.Sum(s => s.Money)
            }).GroupJoin(returnPrePayment, a => a.CreationTime, b => b.CreationTime, (a, b) => new
            {
                a.CreationTime,
                a.Income,
                Expenses = a.Money + b.Sum(s => s.Money)
            }).Select(s => new DailyIncomeAndExpensesDto
            {
                Date = s.CreationTime,
                Income = s.Income,
                Expenses = s.Expenses,
                Difference = Math.Abs(s.Income - s.Expenses)
            });

            return await data.OrderByDescending(o => o.Date).ToListAsync();
        }


        public async Task<ReceivableStatementOutputDto> GetReceivableStatementDataAsync(int pageIdx, int pageSize, DateTime? beginTime, DateTime? endTime, string restaurantIds)
        {
            var factory = (await base.GetCurrentUserAsync()).FactoryinfoId;
            ReceivableStatementOutputDto dto = new ReceivableStatementOutputDto();
            var setmentQuery = _repositorySettlementInfo.GetAll();



            var query = _repositorySettlementInfo.GetAllIncluding(o => o.RestaurantInfoModel, o => o.EmployeeDriverDao).Where(o => o.FactoryinfoId == factory && (o.RestaurantPayStatus == RestaurantPayStatus.未收款 || o.RestaurantPayStatus == RestaurantPayStatus.部分收款 || o.RestaurantPayStatus == RestaurantPayStatus.已收完款)).Select(o => new ReceivableStatementDetailDto
            {
                Id = o.Id,
                BusinessType = BusinessType.收据,
                RestaurantId = o.Restaurantid,
                DocumentNumber = o.CreationNumber,
                CreationTime = o.CreationTime,
                AddReceivable = o.Totalprice,
                TakeReceivable = 0m,
                TotalDiscount = o.Discountprice,
                UsePrePayment = 0m
            }).Union(_repositoryReceiptInfo.GetAllIncluding(o => o.RestaurantInfoModel).Where(o => o.FactoryinfoId == factory & o.ToVoid == ToVoidStatus.未作废).GroupJoin(_repositoryReceiptInfoBySettlementModel.GetAll().Where(o => o.FactoryinfoId == factory && o.ToVoidStatus == ToVoidStatus.未作废), i => i.Id, j => j.ReceiptInfoId, (i, j) => new
            {
                i.Id,
                i.RestaurantId,
                DocumentNumber = i.ReceiptInfoNumber,
                CreationTime = i.CreationTime,
                TakeReceivable = j.Sum(o=>o.TaskBackAmount),
                TotalDiscount = j.Sum(o => o.PreferentialAmount),
                UsePrePayment = j.Sum(o => o.UsePrePayment)
            }).Select(o => new ReceivableStatementDetailDto
            {
                Id = o.Id,
                BusinessType = BusinessType.收款单,
                RestaurantId = o.RestaurantId,
                DocumentNumber = o.DocumentNumber,
                CreationTime = o.CreationTime,
                AddReceivable = 0m,
                TakeReceivable = o.TakeReceivable,
                TotalDiscount = o.TotalDiscount,
                UsePrePayment = o.UsePrePayment
            }));

            var k = _repositorySettlementInfo.GetAllIncluding(o => o.RestaurantInfoModel, o => o.EmployeeDriverDao).Where(o => o.FactoryinfoId == factory && (o.RestaurantPayStatus == RestaurantPayStatus.未收款 || o.RestaurantPayStatus == RestaurantPayStatus.部分收款 || o.RestaurantPayStatus == RestaurantPayStatus.已收完款)).Select(o => new ReceivableStatementDetailDto
            {
                Id = o.Id,
                BusinessType = BusinessType.收据,
                RestaurantId = o.Restaurantid,
                DocumentNumber = o.CreationNumber,
                CreationTime = o.CreationTime,
                AddReceivable = o.Actualprice,
                TakeReceivable = 0m,
                TotalDiscount = 0,
                UsePrePayment = 0m
            }).Union(_repositoryReceiptInfo.GetAllIncluding(o => o.RestaurantInfoModel).Where(o => o.FactoryinfoId == factory & o.ToVoid == ToVoidStatus.未作废).GroupJoin(_repositoryReceiptInfoBySettlementModel.GetAll().Where(o => o.FactoryinfoId == factory && o.ToVoidStatus == ToVoidStatus.未作废), i => i.Id, j => j.ReceiptInfoId, (i, j) => new
            {
                i.Id,
                i.RestaurantId,
                DocumentNumber = i.ReceiptInfoNumber,
                CreationTime = i.CreationTime,
                TakeReceivable = j.Sum(o => o.TaskBackAmount),
                TotalDiscount = j.Sum(o => o.PreferentialAmount),
                UsePrePayment = j.Sum(o => o.UsePrePayment)
            }).Select(o => new ReceivableStatementDetailDto
            {
                Id = o.Id,
                BusinessType = BusinessType.收款单,
                RestaurantId = o.RestaurantId,
                DocumentNumber = o.DocumentNumber,
                CreationTime = o.CreationTime,
                AddReceivable = 0m,
                TakeReceivable = o.TakeReceivable,
                TotalDiscount = o.TotalDiscount,
                UsePrePayment = o.UsePrePayment
            }));


            if (beginTime.HasValue) {
                query = query.Where(o => o.CreationTime > beginTime);
                k = k.Where(o => o.CreationTime < beginTime);
              
            }
               

            if (endTime.HasValue)
                query = query.Where(o => o.CreationTime < endTime.Value.AddDays(1));

            if (!string.IsNullOrEmpty(restaurantIds))
            {
                string[] ids = restaurantIds.Split('|');
                List<Guid> guids = new List<Guid>();
                foreach (var item in ids)
                {
                    guids.Add(new Guid(item));
                }

                query = query.Where(o => guids.Any(s => s == o.RestaurantId));
                k = k.Where(o => guids.Any(s => s == o.RestaurantId));
            }

            var querys = query;

            dto.FinalAddReceivable = querys.Sum(o => o.AddReceivable);
            dto.FinalTakeReceivable = querys.Sum(o => o.TakeReceivable);
            dto.FinalTotalDiscount = querys.Sum(o => o.TotalDiscount);
            dto.FinalUsePrePayment = querys.Sum(o => o.UsePrePayment);

          
            

           
            dto.ReceivableStatementDetail = query.OrderBy(o => o.CreationTime).ThenBy(o => o.RestaurantId).ToPagedList(pageIdx, pageSize);

            var m = setmentQuery.Where(o => o.FactoryinfoId == factory && (o.RestaurantPayStatus == RestaurantPayStatus.未收款 || o.RestaurantPayStatus == RestaurantPayStatus.部分收款 || o.RestaurantPayStatus==RestaurantPayStatus.已收完款 ));

            if (pageIdx == 1)
            {
                if (beginTime.HasValue)
                {
                    //期初应收
                    m = m.Where(o => o.CreationTime < beginTime.Value);

                }
                //if (endTime.HasValue)
                //    m = m.Where(o => o.CreationTime <= endTime.Value.AddDays(1));


                dto.InitialReceivables=m.Sum(o => o.Actualprice);
            }
            else
            {
                if (dto.ReceivableStatementDetail.Count() > 0)
                {
                    dto.InitialReceivables = m.Where(o => o.CreationTime < dto.ReceivableStatementDetail.FirstOrDefault().CreationTime).Sum(o => o.Actualprice); ;
                  

                }

            }
            
            dto.InitialReceivables = k.Sum(o =>o.AddReceivable-(o.TakeReceivable + o.TotalDiscount + o.UsePrePayment));

            dto.FinalReceivables = dto.InitialReceivables + dto.ReceivableStatementDetail.Sum(s=>s.AddReceivable) - dto.ReceivableStatementDetail.Sum(o =>o.TakeReceivable + o.TotalDiscount + o.UsePrePayment);
            return dto;
        }


        public async Task<List<ReceivableStatementDetailDto>> GetReceivableStatementListAsync(DateTime? beginTime, DateTime? endTime, string restaurantIds)
        {
            var factory = (await base.GetCurrentUserAsync()).FactoryinfoId;

            List<ReceivableStatementDetailDto> list = new List<ReceivableStatementDetailDto>();

            var setmentQuery = _repositorySettlementInfo.GetAll();


            var receiv = _repositoryReceiptInfo.GetAllIncluding(o => o.RestaurantInfoModel).Where(o => o.FactoryinfoId == factory && o.ToVoid==ToVoidStatus.未作废).GroupJoin(_repositoryReceiptInfoBySettlementModel.GetAll().Where(o => o.FactoryinfoId == factory && o.ToVoidStatus == ToVoidStatus.未作废), i => i.Id, j => j.ReceiptInfoId, (i, j) => new
            {
                i.Id,
                i.RestaurantId,
                DocumentNumber = i.ReceiptInfoNumber,
                CreationTime = i.CreationTime,
                TakeReceivable = i.ActualAmount,
                TotalDiscount = j.Sum(o => o.PreferentialAmount),
                UsePrePayment = j.Sum(o => o.UsePrePayment)
            }).Select(o => new ReceivableStatementDetailDto
            {
                Id = o.Id,
                BusinessType = BusinessType.收款单,
                RestaurantId = o.RestaurantId,
                DocumentNumber = o.DocumentNumber,
                CreationTime = o.CreationTime,
                AddReceivable = 0m,
                TakeReceivable = o.TakeReceivable,
                TotalDiscount = o.TotalDiscount,
                UsePrePayment = o.UsePrePayment
            });


            var query = _repositorySettlementInfo.GetAllIncluding(o => o.RestaurantInfoModel, o => o.EmployeeDriverDao).Where(o => o.FactoryinfoId == factory && (o.RestaurantPayStatus == RestaurantPayStatus.未收款 || o.RestaurantPayStatus == RestaurantPayStatus.部分收款 || o.RestaurantPayStatus == RestaurantPayStatus.已收完款)).Select(o => new ReceivableStatementDetailDto
            {
                Id = o.Id,
                BusinessType = BusinessType.收据,
                RestaurantId = o.Restaurantid,
                DocumentNumber = o.CreationNumber,
                CreationTime = o.CreationTime,
                AddReceivable = o.Totalprice,
                TakeReceivable = 0m,
                TotalDiscount = o.Discountprice,
                UsePrePayment = o.UsePrePayment
            }).Union(receiv);

            if (beginTime.HasValue)
                query = query.Where(o => o.CreationTime > beginTime);

            if (endTime.HasValue)
                query = query.Where(o => o.CreationTime < endTime.Value.AddDays(1));

            if (!string.IsNullOrEmpty(restaurantIds))
            {
                string[] ids = restaurantIds.Split('|');
                List<Guid> guids = new List<Guid>();
                foreach (var item in ids)
                {
                    guids.Add(new Guid(item));
                }

                query = query.Where(o => guids.Any(s => s == o.RestaurantId));
            }

            return await query.ToListAsync();
        }

        /// <summary>
        /// 获取待审核的任务数
        /// </summary>
        /// <returns></returns>
        public async Task<List<PendingTaskDto>> GetPendingTaskListAsync()
        {
            var user = (await base.GetCurrentUserAsync());
            var loadCar = _repositoryLoadCar.GetAll().Where(o => o.FactoryinfoId == user.FactoryinfoId && o.ExamineStatus == Core.Restaurant.ExamineStatus.未审核);
            var settlement = _repositorySettlementInfo.GetAll().Where(o => o.FactoryinfoId == user.FactoryinfoId && o.ExamineStatus == Core.SettlementInfoModel.ExamineStatus.未审核 && o.RestaurantPayStatus != RestaurantPayStatus.作废);
            var receipt = _repositoryReceiptInfo.GetAll().Where(o => o.FactoryinfoId == user.FactoryinfoId && o.ToVoid == ToVoidStatus.未作废 && o.ReceiptInfoStatus != ReceiptInfoStatus.已审核);
            var collectDeposit = _repositoryDeposit.GetAll().Where(o => o.DepositType == DepositType.收押金 && o.FactoryinfoId == user.FactoryinfoId && o.DepositStatus != DepositStatus.已审核);
            var returnDeposit = _repositoryDeposit.GetAll().Where(o => o.DepositType == DepositType.退押金 && o.FactoryinfoId == user.FactoryinfoId && o.DepositStatus != DepositStatus.已审核);
            var collectPrepayment = _repositoryPrePayment.GetAll().Where(o => o.PrePaymentInfoType == PrePaymentInfoType.收预交金 && o.FactoryinfoId == user.FactoryinfoId && o.PrePaymentInfoStatus != PrePaymentInfoStatus.已审核);
            var returnPrepayment = _repositoryPrePayment.GetAll().Where(o => o.PrePaymentInfoType == PrePaymentInfoType.退预交金 && o.FactoryinfoId == user.FactoryinfoId && o.PrePaymentInfoStatus != PrePaymentInfoStatus.已审核);

            var data = loadCar.Select(s => new {Url= "/Distribution/LoadingInvoice", BillType = BillTypeEnum.装车单, TaskCount = loadCar.Count() });
            data = data.Union(settlement.Select(s => new { Url = "/Settlement/Index", BillType = BillTypeEnum.收据, TaskCount = settlement.Count() }));
            data = data.Union(receipt.Select(s => new { Url = "/Receipt/Index", BillType = BillTypeEnum.收款单, TaskCount = receipt.Count() }));
            data = data.Union(collectDeposit.Select(s => new { Url = "/Deposit/CollectDeposit", BillType = BillTypeEnum.收押金, TaskCount = collectDeposit.Count() }));
            data = data.Union(returnDeposit.Select(s => new { Url = "/Deposit/ReturnDeposit", BillType = BillTypeEnum.退押金, TaskCount = returnDeposit.Count() }));
            data = data.Union(collectPrepayment.Select(s => new { Url = "/Settlement/AdvancePayment", BillType = BillTypeEnum.预收款单, TaskCount = collectPrepayment.Count() }));
            data = data.Union(returnPrepayment.Select(s => new { Url = "/Settlement/RefundPayment", BillType = BillTypeEnum.退还预收款, TaskCount = returnPrepayment.Count() }));

            return data.Select(s => new PendingTaskDto { Url = s.Url, BillType = s.BillType, TaskCount = s.TaskCount }).ToList();
        }
    }

}
